import queue
import threading
import time
import traceback  # 添加在文件顶部

from DrissionPage.errors import ElementNotFoundError
from email_permission import email_list
import pandas as pd
from DrissionPage import Chromium, ChromiumOptions, SessionOptions
from DrissionPage.common import Keys
from DrissionPage.common import Settings

from read_search_file import get_complete_sheet1, get_search_comp, get_creative_name
from loguru import logger
from datetime import datetime
import os

browser_path = os.path.join(os.path.dirname(__file__), 'Chrome', 'chrome.exe')
# .set_paths(local_port=9888, browser_path=browser_path)

lock = threading.Lock()
Settings.set_language("zh_cn")
# TODO 切换商销配置浏览器
# co = ChromiumOptions(read_file=False).set_paths(browser_path=browser_path)  # 读取浏览器方式新建配置对象
co = ChromiumOptions(read_file=False)  # 不读取文件方式新建配置对象
so = SessionOptions(read_file=False)
browser = Chromium(addr_or_opts=co, session_options=so)

def log_message(log_callback, message, color=None):
    if callable(log_callback):
        log_callback(message, color) if color else log_callback(message)

def is_number(value):
    return type(value) in (int, float, complex)

# tag:div@@class=flexible@@text()=点击成本控制
    # plan_next_button_ele = plan_view_tab.ele('tag:span@@class=d-text --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()= 下一步 ').parent(2)
    # plan_next_button_ele.scroll.to_see()
    # # plan_next_button_ele.click(by_js=True)  # 点击下一步
    # # 处理操作频繁
    # handle_operate_too_fast(plan_next_button_ele, plan_view_tab, plan, log_callback)
    #
    # if plan_view_tab.ele('@text():推广计划名称已存在', timeout=1):
    #     log_message(log_callback, f"计划名称:【{plan}】 - 已存在", "red")
    #     return
    #
    # print(f"开始进入创建单元页面:unit_view_tab{plan_view_tab.title}")
    # create_unit(plan_view_tab, row_excel, browser, file_path, plan_next_button_ele, log_callback)

def handle_operate_too_fast(plan_next_button_ele, plan_view_tab, plan, log_callback):
    max_retries = 10  # 最大重试次数
    retry_count = 0
    while retry_count < max_retries:
        # # 先检查是否已经进入下一页
        # if plan_view_tab.ele('tag:input@@class=d-text@@placeholder=请输入你的单元名称', timeout=2):  # 下一页的标识元素
        #     break
        plan_next_button_ele.click(by_js=True)

        if plan_view_tab.ele('@text():操作频繁', timeout=2):
            log_message(log_callback, f"创建计划页面【{plan}】 - 触发操作频繁,正在重试({retry_count + 1}/{max_retries})", "red")
            logger.info(f"操作频繁，等待后重试 ({retry_count + 1}/{max_retries})")
            time.sleep(2 * (retry_count + 1))
            # try:
            #     plan_next_button_ele.click(by_js=True)
            # except NoRectError:
            #     log_message(log_callback, f"创建计划页面的下一步没有找到:{plan} - 页面已跳转，停止重试", "green")
            #     break
            retry_count += 1
        else:
            break

    if retry_count == max_retries:
        logger.error("已达到最大重试次数，仍然操作频繁")
        log_message(log_callback, f"计划名称: 【{plan}】 - 已达到最大重试次数，仍然操作频繁", "red")
    else:
        log_message(log_callback, f"计划名称【{plan}】-在重试({retry_count + 1}/{max_retries})次后成功执行下一步", "green")
        logger.info("操作成功执行")


'''点击新建计划'''
def insert_plan(row_excel, create_plan_tab, file_path, log_callback, df_sheet):
    plan_ele = create_plan_tab.ele('tag:button@@text():新建广告')

    ignore_pop_ele = create_plan_tab.ele('@text()=暂时忽略', timeout=0.5)
    if ignore_pop_ele:
        ignore_pop_ele.run_js('this.click();')
    try:
        lock.acquire()
        plan_view_tab = plan_ele.click.for_new_tab(by_js=True)  # 点击新建广告按钮并打开创建计划表单页面
        plan_view_tab.wait.title_change("新建推广 - 小红书乘风")
    finally:
        lock.release()

    create_plan(plan_view_tab, row_excel, file_path, log_callback, df_sheet)

def worker(task_queue, create_plan_tab, file_path, log_callback, df_sheet):
    """
    工作线程函数，从队列中获取任务并执行自动化操作
    """
    while True:
        row_excel = task_queue.get()
        if row_excel is None:  # 结束信号
            break
        try:
            log_message(log_callback, f"处理中: {row_excel['计划名']}")
            insert_plan(row_excel, create_plan_tab, file_path, log_callback, df_sheet)
        except Exception as e:
            # 获取完整错误信息
            error_msg = f"{type(e).__name__}: {str(e)}"
            error_trace = traceback.format_exc()  # 获取完整堆栈跟踪
            # 前端显示简化错误
            log_message(log_callback, f"执行错误: {row_excel['计划名']} - {error_msg}", "red")

            # 日志记录完整错误
            logger.error(f"错误时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
                         f"计划名: {row_excel['计划名']}\n"
                         f"错误类型: {type(e).__name__}\n"
                         f"错误详情: {error_msg}\n"
                         f"堆栈跟踪:\n{error_trace}")
        finally:
            task_queue.task_done()
    log_message(log_callback, f"全部计划处理完毕", "green")  # 全部处理完毕

def start_sub_account_url(file_path, concurrency_num=2, log_callback=None):
    df_sheet = get_complete_sheet1(file_path)
    all_columns = df_sheet.columns
    logger.info(f"所有列:{df_sheet.columns}")

    if int(concurrency_num) > 5:
        log_message(log_callback, f"并发数量暂时最大为5", "red")
        return
    if '关联定向包' not in all_columns:
        log_message(log_callback, f"表格中缺少【关联定向包】列", "red")
        return
    if '商品ID' not in all_columns:
        log_message(log_callback, f"表格中缺少【商品ID】列", "red")
        return
    if '推广笔记' not in all_columns:
        log_message(log_callback, f"表格中缺少【推广笔记】列", "red")
        return
    if '账号ID' not in all_columns:
        log_message(log_callback, f"表格中缺少【账号ID】列", "red")
        return
    if '创意名称' not in all_columns:
        log_message(log_callback, f"表格中缺少【创意名称】列", "red")
        return

    task_queue = queue.Queue()
    # 将 Excel 数据逐行放入队列中
    for index, row in df_sheet.iterrows():
        task_queue.put(row)

    # 打开合作伙伴平台页面
    account_id = df_sheet['账号ID']
    text_account_id = account_id[0].strip()

    account_tab = browser.new_tab('https://partner.xiaohongshu.com/partner/subAccount-list')

    # TODO 加一个校验步骤， 不是叁柒的所属邮箱直接驳回
    account_tab.ele('tag:span@@class=d-text --color-static --color-text-paragraph --size-text-paragraph text label@@text()^登陆邮箱：').next().child().next().click(by_js=True)
    account_tab.wait(0.5)
    email_str = account_tab.ele('tag:span@@class=d-text --color-static --color-text-paragraph --size-text-paragraph text label@@text()^登陆邮箱：').next().child().text
    email_permission_list = email_list(log_callback)
    if email_str not in email_permission_list:
        log_message(log_callback, f"当前邮箱账号:【{email_str}】暂无权限使用", "red")
        return

    # 输入子账号ID
    account_tab.ele('tag:input@@class=el-input__inner@@type=text@@autocomplete=off@@placeholder=请输入').input(text_account_id)
    account_tab.ele('tag:button@@id=search-btn--1').click(by_js=True)

    search_none_ele = account_tab.ele('tag:tr@@class=d-table__empty-row@@text()=暂无数据', timeout=0.5)
    if search_none_ele:
        log_message(log_callback, f"合作伙伴平台子账号ID:{text_account_id}搜索结果为空, 检查表格第一行子账号ID, 或者检查是否登录合作伙伴平台", "red")
        return

    account_tab.ele('tag:span@@text():跳转', timeout=2).hover()

    plan_tab_arr = []  # 新建计划标签页对象数组
    threads = []
    jg_ele = account_tab.ele('tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis@@text():乘风平台', timeout=2)

    if jg_ele:
        create_plan_tab = jg_ele.click.for_new_tab(by_js=True)
        create_plan_tab.wait.title_change("首页 - 小红书乘风")

        plan_url = create_plan_tab.url
        print(f"点完聚光平台以后跳转的tab:{create_plan_tab.url}")
        plan_tab_arr.append(create_plan_tab)

        if int(concurrency_num) > 1:
            for _ in range(concurrency_num - 1):
                plan_tab_arr.append(browser.new_tab(plan_url))

    for plan_tab in plan_tab_arr:
        logger.info(f"开始创建线程: {threading.current_thread().name} - 给当前线程分配的新建计划tab标签页:{id(plan_tab)}")
        t = threading.Thread(target=worker, args=(task_queue, plan_tab, file_path, log_callback, df_sheet))
        t.start()
        time.sleep(2)
        threads.append(t)

    task_queue.join()

    # 发送结束信号给所有线程
    for _ in range(len(threads)):
        task_queue.put(None)

    # 等待所有线程结束
    for t in threads:
        t.join()

def handle_invalid_note_ids(invalid_note_ids, plan_view_tab, log_callback, note_title_str_arr, actual_note_id_arr):
    """处理无效笔记ID的搜索流程"""
    plan_view_tab.ele('tag:div@@class=add-block', timeout=2).ele('tag:span@@text()=添加笔记').click(by_js=True)
    plan_view_tab.ele('tag:input@@placeholder=搜索笔记内容或笔记ID', timeout=2).wait.displayed()

    for note_id in invalid_note_ids:
        note_id = note_id.strip()
        none_data_str = click_every_content_choose_note_id('我的笔记', note_id, plan_view_tab)
        if none_data_str: # 我的笔记没有
            none_data_str = click_every_content_choose_note_id('企业笔记', note_id, plan_view_tab)
            if none_data_str: # 企业笔记没有
                none_data_str = click_every_content_choose_note_id('广告素材', note_id, plan_view_tab)
                if none_data_str:
                    log_message(log_callback, f'该条笔记ID:{note_id}在所有模块搜寻无结果', "red")
                    continue
                else:
                    choose_and_save_note_id(note_id, plan_view_tab, log_callback, note_title_str_arr, actual_note_id_arr)
                    continue
            else:
                choose_and_save_note_id(note_id, plan_view_tab, log_callback, note_title_str_arr, actual_note_id_arr)
                continue
        else:
            choose_and_save_note_id(note_id, plan_view_tab, log_callback, note_title_str_arr, actual_note_id_arr)
            continue

    plan_view_tab.ele('tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=保存', timeout=2).parent(2).click(by_js=True)

mock_click_js = """
function triggerFullClick(element) {
  // 1. 触发鼠标按下
  element.dispatchEvent(new MouseEvent('mousedown', {
    bubbles: true,
    cancelable: true,
    view: window
  }));

  // 2. 触发获取焦点
  element.focus();
  element.dispatchEvent(new Event('focus', {bubbles: true}));

  // 3. 触发鼠标释放
  element.dispatchEvent(new MouseEvent('mouseup', {
    bubbles: true,
    view: window
  }));

  // 4. 触发最终点击
  element.dispatchEvent(new MouseEvent('click', {
    bubbles: true,
    view: window
  }));
}

// 执行函数
triggerFullClick(this);
"""

    # handle_all_excel_data(df_sheet, file_path, log_callback)
def create_plan(plan_view_tab, row_excel, file_path, log_callback=None, df_sheet=None):
    # plan_view_tab.set.scroll.smooth(on_off=False)
    plan_view_tab.wait.load_start()
    plan_view_tab.wait(2.5)

    plan = row_excel['计划名'].strip()
    market_target = row_excel['营销目标'].strip()
    market_scene = row_excel['营销场景'].strip()
    ad_type = row_excel['广告类型'].strip()
    delivery_mode = row_excel['投放模式'].strip()
    recom_note_id = row_excel['推广笔记'].strip()
    raw_creative_name = row_excel['创意名称'].strip()
    goods_ids = row_excel['商品ID']
    recom_target = row_excel['推广目标'].strip()
    delivery_type = row_excel['投放方式'].strip()
    bidding_price = row_excel['出价']
    plan_budget = row_excel['预算']
    delivery_rate = row_excel['投放速率']
    relative_pack = row_excel['关联定向包']
    crowed_target = row_excel['人群定向']
    row_trans_comp = row_excel['转化组件']
    auto_optimize = row_excel['自动优化']

    gender = row_excel['性别']
    area = row_excel['地域']
    age = row_excel['年龄']

    if market_target == '直播推广':
        plan_view_tab.ele("#basic-info").ele(f'tag:span@@text()=支持笔记&直播卡主体，吸引用户进入直播间下单', timeout=2).parent(2).click(by_js=True)
        plan_view_tab.wait(1)
    if market_target == '商品推广':
        plan_view_tab.ele("#basic-info").ele(f'tag:span@@text()=支持笔记主体，引导用户进入店铺下单', timeout=2).parent(2).click(by_js=True)
        plan_view_tab.wait(1)

    plan_view_tab.ele("#basic-info").ele(f'tag:span@@text()={market_scene}', timeout=2).click(by_js=True)
    plan_view_tab.wait(0.5)
    plan_view_tab.ele("#basic-info").ele(f'tag:span@@text()={ad_type}', timeout=2).click(by_js=True)
    plan_view_tab.ele("#basic-info").ele(f'tag:span@@text()={delivery_mode}', timeout=2).click(by_js=True)

    # 如果是直播推广, 需要添加开播账号和推广主体
    if market_target == '直播推广' and market_scene != '直播预告':
        if ('我的直播间' or '授权直播间') not in df_sheet.columns:
            log_message(log_callback, f"营销目标为直播推广时, [我的直播间],[授权直播间]表头不能为空")
            return
        if '推广主体(是否推广直播间)' not in df_sheet.columns:
            log_message(log_callback, f"营销目标为直播推广时, [推广主体]表头不能为空")
            return

        my_stream_account = str(row_excel['我的直播间']).strip()
        stream_account = str(row_excel['授权直播间']).strip()

        is_promotion_subject = row_excel['推广主体(是否推广直播间)'].strip()
        if is_promotion_subject not in ('是', '否'):
            log_message(log_callback, f"推广主体(是否推广直播间) 字段必须为“是”或“否”，当前值：{is_promotion_subject}", "red")
            return

        # 授权直播间
        if pd.notna(stream_account) and stream_account != 'nan':
            if plan_view_tab.ele(f"tag:div@@class=d-text d-select-placeholder d-text-ellipsis d-text-nowrap@@text()=请选择直播间或按用户ID搜索", timeout=2):
                plan_view_tab.ele(f"tag:div@@class=d-text d-select-placeholder d-text-ellipsis d-text-nowrap@@text()=请选择直播间或按用户ID搜索", timeout=2).parent(4).run_js(mock_click_js)
                time.sleep(1)
                plan_view_tab.ele(f"@text()=授权直播间", timeout=2).run_js('this.click();')
                if plan_view_tab.ele(f"tag:span@@class=d-text --color-static --color-text-description --size-text-small@@text()${stream_account}", timeout=2):
                    option_item_account_ele = plan_view_tab.ele(f"tag:span@@class=d-text --color-static --color-text-description --size-text-small@@text()${stream_account}")
                    option_item_account_ele.run_js('this.click();')
                    # plan_view_tab.ele('tag:div@@text()=请选择直播间或按用户ID搜索').click(by_js=True)
                    # plan_view_tab.ele(f"tag:span@@class=d-text --color-static --color-text-description --size-text-small@@text()${stream_account}").parent(4).prev().prev().click(by_js=True)
                else:
                    print(f"当前计划名: {plan} - 授权直播间 - 开播账号: {stream_account}选项不存在")
                    log_message(log_callback, f"当前计划名: {plan} - 开播账号: {stream_account}选项不存在", "red")
                    return
        else:
            # 我的直播间
            if pd.notna(my_stream_account) and my_stream_account != 'nan':
                if plan_view_tab.ele(f"tag:div@@class=d-text d-select-placeholder d-text-ellipsis d-text-nowrap@@text()=请选择直播间或按用户ID搜索", timeout=2):
                    plan_view_tab.ele(f"tag:div@@class=d-text d-select-placeholder d-text-ellipsis d-text-nowrap@@text()=请选择直播间或按用户ID搜索", timeout=2).parent(4).run_js(mock_click_js)
                    plan_view_tab.wait(1)
                    if plan_view_tab.ele(f"tag:span@@class=d-text --color-static --color-text-description --size-text-small@@text()${my_stream_account}", timeout=2):
                        option_item_account_ele = plan_view_tab.ele(f"tag:span@@class=d-text --color-static --color-text-description --size-text-small@@text()${my_stream_account}")
                        option_item_account_ele.run_js('this.click();')
                        # plan_view_tab.ele('tag:div@@text()=请选择直播间或按用户ID搜索').click(by_js=True)
                        # plan_view_tab.ele(f"tag:span@@class=d-text --color-static --color-text-description --size-text-small@@text()${stream_account}").parent(4).prev().prev().click(by_js=True)
                    else:
                        print(f"当前计划名: {plan} - 我的直播间 - 开播账号: {my_stream_account}选项不存在")
                        log_message(log_callback, f"当前计划名: {plan} - 开播账号: {my_stream_account}选项不存在", "red")
                        return

        # 推广主体
        if plan_view_tab.ele('tag:span@@class=checkbox-label@@text()=直播间', timeout=2):
            stream_check_status = plan_view_tab.ele('tag:span@@class=checkbox-label@@text()=直播间').parent(1).prev().prev().attr('class')
            if is_promotion_subject == '否':
                if 'unchecked' not in stream_check_status:
                    plan_view_tab.ele('tag:span@@class=checkbox-label@@text()=直播间').parent(1).prev().prev().click(by_js=True)
            if is_promotion_subject == '是':
                if 'unchecked' in stream_check_status:
                    plan_view_tab.ele('tag:span@@class=checkbox-label@@text()=直播间').parent(1).prev().prev().click(by_js=True)

    #  把原始的笔记ID和创意名称位置记住
    note_id_arr = recom_note_id.strip().split('\n')
    creative_name_arr = raw_creative_name.split('\n')
    note_id_to_creative_name = dict(zip(note_id_arr, creative_name_arr))

    # 先批量添加笔记ID
    # if recom_note_id:
    #     plan_view_tab.ele("tag:a@@class=d-text d-link --color-primary --size-text-paragraph@@text()=ID批量添加").scroll.to_center()
    #     plan_view_tab.ele("tag:a@@class=d-text d-link --color-primary --size-text-paragraph@@text()=ID批量添加").click(by_js=True)
    # batch_add_note_id_content = plan_view_tab.ele("tag:div@@class=d-modal d-modal-centered batch-add-note-modal", timeout=3)
    #
    # batch_add_note_id_content.ele('tag:input@@class=d-text@@type=text@@placeholder=回车输入多个 ID，最多 100 条').run_js('this.focus();')
    # for note in note_id_arr:
    #     note = str(note).strip()
    #     plan_view_tab.actions.input(note).input(Keys.ENTER).wait(0.1)
    #
    # batch_add_note_id_content.ele('tag:a@@class=d-text d-link --color-primary --size-text-paragraph btn-validate@@text()=搜索').click(by_js=True)
    #
    # plan_view_tab.wait(1)

    # invalid_note_ids = []
    # if plan_view_tab.ele('tag:span@@text():ID搜索失败', timeout=2):
    #     invalid_note_ids = plan_view_tab.eles('tag:input@@placeholder=回车输入多个 ID，最多 100 条', timeout=2).get.attrs('value')
    #     logger.info(invalid_note_ids)
    #     log_message(log_callback, f"当前计划:{plan}-下列笔记ID {invalid_note_ids} 批量搜索失败, 后续转为我的笔记-企业笔记-广告素材搜索", "red")
    #
    # confirm_add_button_ele = batch_add_note_id_content.ele('tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=确认添加', timeout=2).parent(2)
    # confirm_add_button_ele.wait.enabled()
    # confirm_add_button_ele.click(by_js=True) ## 确认添加笔记
    #
    # confirm_add_button_ele.wait(2)

    # 如果存在批量搜不出来的笔记,进行挨个搜索
    note_title_str_arr = []
    actual_note_id_arr = []
    if note_id_arr:
        handle_invalid_note_ids(note_id_arr, plan_view_tab, log_callback, note_title_str_arr, actual_note_id_arr)

    note_id_to_title = dict(zip(actual_note_id_arr, note_title_str_arr))
    # 构建标题 -> 创意名称 的映射
    title_to_creative_name = {
        title: note_id_to_creative_name[note_id] for note_id, title in note_id_to_title.items() if note_id in note_id_to_creative_name
    }

    ## 如果商品ID不为空,挂载商品ID
    if pd.notna(goods_ids) and market_scene != '直播预告':
        note_blocks = plan_view_tab.ele('tag:div@@class:list-container').eles('.note-block')
        if len(note_blocks) > 0:
            first_note_block = note_blocks[0]
            first_note_block.ele('.note-info').ele('.note-good').next().child().click(by_js=True) # 点击第一个笔记块的修改商品

        plan_view_tab.ele('.good-list').wait.displayed()

        all_goods_selected = plan_view_tab.ele('tag:table@@class=d-new-table d-table-auto d-table--fixed').ele('.d-table__body').eles('tag:tr')
        logger.info(f"当前所有商品数量:{len(all_goods_selected)}")

        first_good_num = get_first_good_num(plan_view_tab)

        good_ids_arr = goods_ids.strip().split('\n')
        for i, good_id in enumerate(good_ids_arr):
            good_id = good_id.strip()
            if first_good_num == 0:
                search_goods(good_id, log_callback, plan_view_tab)
                continue
            else:
                # 先取消掉之前选中的商品ID
                if i == 0:
                    goods_is_checked_str = plan_view_tab.ele('tag:span@@text()= 仅看已选中 ').prev().child().child().child().attr('class')
                    if 'uncheck' in goods_is_checked_str:
                        plan_view_tab.ele('tag:span@@text()= 仅看已选中 ').prev().click(by_js=True)  # 开启
                        plan_view_tab.wait(1)

                        if plan_view_tab.ele('tag:thead@@class=d-table__header').after('tag:div@@class=d-grid d-checkbox d-checkbox-main d-clickable', timeout=2):
                            plan_view_tab.ele('tag:thead@@class=d-table__header').after('tag:div@@class=d-grid d-checkbox d-checkbox-main d-clickable').click(by_js=True)  # 取消之前的

                        plan_view_tab.ele('tag:span@@text()= 仅看已选中 ').prev().click(by_js=True)  # 关闭
                        plan_view_tab.wait(1)
                # plan_view_tab.ele('tag:span@@class:indeterminate').parent(1).multi(2)
                search_goods(good_id, log_callback, plan_view_tab)
                continue

        plan_view_tab.ele('tag:a@@text()= 应用至所有笔记 ', timeout=2).click(by_js=True) # 点击应用至所有笔记

        if confirm_goods_list_button := plan_view_tab.ele('tag:span@@text()=确定', timeout=2):
            confirm_goods_list_button.parent(2).click(by_js=True)

        if plan_view_tab.ele('@text():已将所选商品应用至本次新增的所有笔记', timeout=2):
            plan_view_tab.ele('tag:span@@text()= 确认关联 ').parent(2).click(by_js=True)

    # 搜一下实际添加的笔记数量
    note_blocks = plan_view_tab.ele('tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph bold@@text()= 推广笔记 ').parent(3).child(index=2).eles('.note-block')

    # 推广目标
    plan_view_tab.ele(f'tag:button@@text()={recom_target}').click(by_js=True)
    # 投放方式
    plan_view_tab.ele(f'tag:button@@text()={delivery_type}').click(by_js=True)

    # 出价
    bidding_price_ele = plan_view_tab.ele('css:#promote-config > div > form > div:nth-child(4) > div > div.d-form-item__wrapper > div > div.d-input-wrapper.d-inline-block > div > div.d-input-number-main > input', timeout=2)
    if bidding_price_ele and bidding_price_ele.states.is_enabled:
        bidding_price_ele.input(bidding_price, clear=True)

    # 直播快投
    if plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph@@text()=直播快投', timeout=1.3):
        if '直播快投' in df_sheet.columns:
            stream_fast = row_excel['直播快投']
            if stream_fast == '不开启'  or stream_fast is None:
                stream_fast_ele = plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph@@text()=直播快投', timeout=2)
                stream_fast_class = stream_fast_ele.parent(3).prev().ele('.d-switch-top').child().attr('class')
                if 'unchecked' not in stream_fast_class:
                    stream_fast_ele.parent(3).prev().ele('.d-switch-top').child().click(by_js=True)

    # 搜索快投
    if plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph@@text()=搜索快投', timeout=1.3):
        if '搜索快投' in df_sheet.columns:
            search_fast = row_excel['搜索快投']
            if search_fast == '不开启' or search_fast is None:
                search_fast_ele = plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph@@text()=搜索快投', timeout=2)
                search_fast_class = search_fast_ele.parent(3).prev().ele('.d-switch-top').child().attr('class')
                if 'unchecked' not in search_fast_class:
                    search_fast_ele.parent(3).prev().ele('.d-switch-top').child().click(by_js=True)


    # 日预算
    if pd.notna(plan_budget):  #预算类型
        if is_number(plan_budget):  ## 指定预算
            plan_view_tab.ele('tag:div@@class=flexible align-center@@text()=自定义预算').parent(3).click(by_js=True)
            if plan_budget_ele := plan_view_tab.ele('tag:div@@class=flexible align-center@@text()=自定义预算').parent(4).next().ele('.d-input-number-main').child():
                plan_budget_ele.scroll.to_center()
                plan_budget_ele.input(plan_budget, clear=True)
        else: ## 不限预算
            plan_view_tab.ele('tag:button@@text()=不限').click(by_js=True)
    # 投放速率
    if plan_view_tab.ele('tag:span@@text()= 投放速率 ', timeout=2):
        delivery_rate_text = plan_view_tab.ele('tag:span@@text()= 投放速率 ', timeout=2)
        if delivery_rate_text:
            if plan_view_tab.ele(f'tag:div@@class=d-button-content@@text()={delivery_rate}', timeout=2):
                plan_view_tab.ele(f'tag:div@@class=d-button-content@@text()={delivery_rate}').click(by_js=True)

    plan_view_tab.ele(f'tag:div@@class=flexible align-center@@text()=智能定向', timeout=2).scroll.to_center()

    ## 关联包
    if pd.notna(relative_pack):
        relative_pack = relative_pack.strip()
        plan_view_tab.ele(f'tag:a@@text()= 关联定向包 ', timeout=2).click(by_js=True)
        plan_view_tab.wait(1)
        if please_choose_ele := plan_view_tab.ele('tag:div@@class=d-text d-select-placeholder d-text-ellipsis d-text-nowrap@@text()=请选择', timeout=2):
            please_choose_ele.wait(0.3).click(by_js=True).input(relative_pack)  # 点击文本框

        if choose_option_ele := plan_view_tab.ele(f'tag:mark@@class=--color-bg-transparent --color-primary@@text()={relative_pack}', timeout=2):
            choose_option_ele.wait(0.3).click(by_js=True)  # 选中选项
        elif span_relative_pack_ele := plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis@@text()={relative_pack}', timeout=2):
            span_relative_pack_ele.parent(4).prev().prev().click(by_js=True)
        else:
            log_message(log_callback, f"当前计划:{plan}没有关联定向包:{relative_pack}", "red")
            plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=取消').parent(2).click(by_js=True)

        time.sleep(1)

        plan_view_tab.ele('tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=确认关联').parent(2).click(by_js=True)
    else:
        ## 定向设置
        if pd.notna(crowed_target) and crowed_target in '智能定向':
            plan_view_tab.ele(f'tag:div@@class=flexible align-center@@text()=智能定向', timeout=2).click(by_js=True)
            # 性别、地域、年龄
            more_target(age, area, gender, plan_view_tab)

    ## 计划信息
    plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph bold@@text()= 计划名称 ', timeout=2).scroll.to_center()
    plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph bold@@text()= 计划名称 ', timeout=2).next().ele('tag:input@@class=d-text@@type=text@@maxlength=50').input(plan, clear=True)

    ## 创意信息
    config_creative_info(file_path, note_id_arr, plan, plan_view_tab, row_trans_comp, log_callback, df_sheet=df_sheet, row_excel=row_excel, title_to_creative_name=title_to_creative_name)

    # 自动优化
    if auto_optimize == '不开启':
        if auto_optimize_ele := plan_view_tab.ele('tag:span@@text()= 自动优化 ', timeout=2):
            auto_optimize_ele.parent(2).next().child().next().click(by_js=True)  # 保存配置

    # 发布推广
    plan_view_tab.ele('tag:span@@text()=发布推广').parent(2).click(by_js=True)  # 发布推广
    time.sleep(2)
    browser.close_tabs(plan_view_tab)

def choose_and_save_note_id(note_id, plan_view_tab, log_callback, note_title_str_arr, actual_note_id_arr):
    try:
        note_id_tr_str = plan_view_tab.ele('tag:div@@text()=笔记信息', timeout=2).parent(3).next().child(index=1).child(index=2).ele('tag:p@@class=truncate').attr('title')
        if note_id in note_id_tr_str:
            clickable_ele = plan_view_tab.ele('tag:div@@text()=笔记信息', timeout=2).parent(3).next().child(index=1).child(index=1).ele('tag:div@@class=d-grid d-checkbox d-checkbox-main d-clickable', timeout=3)
            if clickable_ele:
                clickable_status_class_str = clickable_ele.child().attr('class')
                if 'unchecked' in clickable_status_class_str:
                    clickable_ele.click(by_js=True) # 选中
                    plan_view_tab.wait(1)
                    note_title_str = plan_view_tab.ele('tag:div@@text()=笔记信息', timeout=2).parent(3).next().child(index=1).child(index=2).ele('tag:p@@class=truncate').prev().child().text
                    note_title_str_arr.append(note_title_str)
                    actual_note_id_arr.append(note_id)

    except ElementNotFoundError as e:
        log_message(log_callback, f'笔记ID:{note_id}无法选中或不存在, 已跳过', "red")
def click_every_content_choose_note_id(content, note_id, plan_view_tab):
    plan_view_tab.ele(f'tag:span@@text()={content}', timeout=2).click(by_js=True)
    plan_view_tab.ele('tag:input@@placeholder=搜索笔记内容或笔记ID', timeout=2).input(note_id, clear=True).input(Keys.ENTER)
    # plan_view_tab.ele('tag:div@@class=d-table-loading').wait.hidden()
    plan_view_tab.wait(1)
    none_data_str = plan_view_tab.ele('tag:div@@text()=笔记信息', timeout=2).parent(3).next().child(index=1).ele('tag:span@@class=d-text --color-static --color-text-description --size-text-description@@text()=暂无数据', timeout=1)
    return none_data_str


def config_creative_info(file_path, note_id_arr, plan, plan_view_tab, row_trans_comp, log_callback, df_sheet=None, row_excel=None, title_to_creative_name=None):
    df_search_comp = get_search_comp(file_path)

    plan_list = df_search_comp['计划名称'].tolist()
    if plan not in plan_list:
        log_message(log_callback, f"计划列表的计划名:【{plan}】 在转化组件sheet页中不存在", "red")

    creative_info_content_ele = plan_view_tab.ele('tag:h5@@text()= 创意信息 ', timeout=2)
    if creative_info_content_ele:
        creative_content_items = plan_view_tab.ele('tag:div@@class=creativity-list', timeout=2).eles('.creativity-container note-creativity-container')
        for i, item in enumerate(creative_content_items):
            item('tag:span@@text()= 创意名称 ').scroll.to_center()  # 滚到转化组件
            creative_title_str = item('tag:span@@class=d-text --color-static --color-text-paragraph --size-text-paragraph creativity-note').text

            item('tag:span@@text()= 创意名称 ').next().child().child().input(title_to_creative_name.get(creative_title_str, ''), clear=True)
            if pd.notna(row_trans_comp) and row_trans_comp != '不使用组件':
                comp_str = item('tag:span@@text()= 转化组件 ').next().child().child().text
                if ' 直播组件 ' == comp_str:
                    continue

                item('tag:span@@text()= 转化组件 ').next().click(by_js=True)  # 点击转化组件详情按钮
                if not df_search_comp.empty:
                    for s in df_search_comp.itertuples():
                        if s.计划名称 != plan:
                            continue

                        top_comment_text = s.置顶评论区文案 if s.置顶评论区文案 else ""
                        search_word = s.搜索词 if s.搜索词 else ""

                        trans_comp = s.组件类型.strip()
                        if plan_view_tab.ele(f'tag:div@@text()={trans_comp}', timeout=2):
                            plan_view_tab.ele(f'tag:div@@text()={trans_comp}').parent(3).click(by_js=True)  # 点击具体组件名称(商品组件或者搜索组件)
                        else:
                            break

                        if trans_comp == '商品组件':
                            plan_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder=请输入评论区文案').input(top_comment_text, clear=True)  # 输入评论区文案

                        if trans_comp == '搜索组件':
                            comp_loc_arr = s.组件位置.strip().split('\n')  ## 组件位置

                            if len(comp_loc_arr) == 2 or '置顶评论区' in comp_loc_arr:  # 评论区文案和搜索词都要
                                plan_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder=请输入评论区文案').input(top_comment_text, clear=True)  # 输入评论区文案
                                plan_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder=请输入搜索词文案').input(search_word, clear=True)  # 输入搜索词
                            else:  # 只有搜索词文案
                                plan_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder=请输入搜索词文案').parent(2).click(search_word, clear=True)  # 点击置顶评论区
                                plan_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder=请输入搜索词文案').input(search_word, clear=True)  # 输入搜索词
                        break

                    if plan_view_tab.ele('tag:span@@text()= 保存配置 ', timeout=2):
                        plan_view_tab.ele('tag:span@@text()= 保存配置 ').click(by_js=True)  # 保存配置
                    elif plan_view_tab.ele('tag:span@@text()= 我知道了 ', timeout=2):
                        plan_view_tab.ele('tag:span@@text()= 我知道了 ').click(by_js=True)
                    else:
                        plan_view_tab.ele('tag:span@@class=d-icon --color-current --color-static --size-icon-default d-drawer-close d-clickable', timeout=2).child().click(by_js=True)


def more_target(age, area, gender, plan_view_tab):
    # 性别
    if gender != '不限' and gender != '全选':
        plan_view_tab.ele(f'tag:div@@class=flexible align-center@@text()={gender.strip()}').parent(3).click(by_js=True)  ## 点击男或女

    # 地域
    plan_view_tab.ele('tag:div@@class=flexible align-center@@text()=自定义').parent(3).click(by_js=True)  ## 点击自定义
    plan_view_tab.ele(f'tag:span@@class=d-text --color-static --color-text-title --size-text-paragraph d-text-nowrap d-text-ellipsis d-checkbox-label@@text()=中国').parent(1).click(by_js=True)  ## 点击中国
    plan_view_tab.ele('tag:span@@text()= 添加地域 ').parent(2).click(by_js=True)  ## 点击自定义

    # 年龄
    if '不限' != age and age != '全选':
        age_arr = age.split('\n')
        for a in age_arr:
            age_ele = plan_view_tab.ele(f'tag:span@@class=checkbox-label@@text()={a.strip()}', timeout=2)
            if age_ele:
                age_ele.parent(2).click(by_js=True)  ## 选中各年龄段
            else:
                continue

def search_goods(good_id, log_callback, plan_view_tab):
    try:
        plan_view_tab.ele('tag:input@@class=d-text@@placeholder=搜索商品名称或ID').input(good_id.strip(), clear=True).input(Keys.ENTER)
        plan_view_tab.wait(1.5)
        if good_id_match := plan_view_tab.ele('.good-info-cell').ele(f'tag:span@@text():{good_id.strip()}', timeout=1.5):
            is_cheked = good_id_match.parent(5).prev().child().child().child().child().attr('class')  ## 查看class判断是否选中
            if 'unchecked' in is_cheked:
                good_id_match.parent(5).prev().child().child().child().click(by_js=True)
                plan_view_tab.wait(0.5)

    except ElementNotFoundError as e:
        log_message(log_callback, f"没有当前商品ID:{good_id}", "red")


def get_first_good_num(plan_view_tab):
    note_blocks = plan_view_tab.ele('tag:div@@class:list-container').eles('.note-block')
    good_num = note_blocks[0].ele('.note-info').ele('.split-line').next().child().next().text if len(note_blocks) > 0 else 0
    logger.info(f"选之后第一个笔记块的商品数量:{good_num}")
    return int(good_num)


if __name__ == '__main__':
    file_path = r'D:\Users\Desktop\袋鼠妈妈闭环笔记测试7.15.xlsx'
    plan_view_tab = browser.latest_tab
    plan_view_tab.get("https://chengfeng.xiaohongshu.com/cf/ad/create?vSellerId=6822efab97bb7c00152aaf89")
    df = get_complete_sheet1(file_path=file_path)

    for index, row_excel in df.iterrows():
        if index == 0:
            create_plan(plan_view_tab, row_excel, file_path, df_sheet=df)
















